package com.kasax.ipcbus.corel;

import android.text.TextUtils;

import com.kasax.ipcbus.bean.RequestBean;
import com.kasax.ipcbus.bean.RequestParameter;
import com.kasax.ipcbus.utils.LogUtils;
import com.kasax.ipcbus.utils.TypeUtils;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TypeCenter {
    private static TypeCenter sOurInstance = new TypeCenter();

    /**
     * 缓存服务: 类名+类
     */
    private ConcurrentHashMap<String, Class> mRawClassMap = new ConcurrentHashMap<>();


    /**
     * 缓存类中的所有的方法:
     * Class + [方法签名, 方法对象]
     */
    private ConcurrentHashMap<Class, ConcurrentHashMap<String, Method>> mRawMethodMap = new ConcurrentHashMap<>();

    private TypeCenter() {

    }

    public static TypeCenter getInstance() {
        return sOurInstance;
    }


    public void register(Class serviceCls) {
        LogUtils.i(getClass(), "register serviceCls: " + serviceCls.getName() + " start");
        registerClass(serviceCls);
        registerMethod(serviceCls);
        LogUtils.i(getClass(), "register serviceCls: " + serviceCls.getName() + " complete");
        showCacheMapInfo();
    }

    private void showCacheMapInfo() {
        LogUtils.i(getClass(), " ----------------------  showCacheMapInfo class-map ----------------------  ");
        for (Map.Entry<String, Class> classEntry : mRawClassMap.entrySet()) {
            LogUtils.i(getClass(), "showCacheMapInfo class-name: " + classEntry.getKey() + " , class-data: " + classEntry.getValue());
        }
        LogUtils.i(getClass(), " ----------------------  showCacheMapInfo class-map-complete ----------------------  ");
        LogUtils.i(getClass(), " ----------------------  showCacheMapInfo mRawMetho-map ----------------------  ");
        for (Map.Entry<Class, ConcurrentHashMap<String, Method>> methodMapEntry : mRawMethodMap.entrySet()) {
            LogUtils.i(getClass(),
                    "showCacheMapInfo methodMapEntry-name: " + methodMapEntry.getKey() + " , methodMapEntry-data: " + methodMapEntry.getValue());
            ConcurrentHashMap<String, Method> methodsMapEntry = methodMapEntry.getValue();
            for (Map.Entry<String, Method> methodEntry : methodsMapEntry.entrySet()) {
                LogUtils.i(getClass(),
                        "showCacheMapInfo methodEntry-name: " + methodEntry.getKey() + " , methodEntry-data: " + methodEntry.getValue());
            }
        }
        LogUtils.i(getClass(), " ----------------------  mRawMetho-map-complete ----------------------  ");
    }

    /**
     * 缓存方法
     *
     * @param serviceCls
     */
    private void registerMethod(Class serviceCls) {
        LogUtils.i(getClass(), "registerMethod serviceCls: " + serviceCls.getName());
        Method[] methods = serviceCls.getMethods();
        for (Method method : methods) {
            mRawMethodMap.putIfAbsent(serviceCls, new ConcurrentHashMap<>());
            ConcurrentHashMap<String, Method> map = mRawMethodMap.get(serviceCls);
            String methodId = TypeUtils.getMethodId(method);
            LogUtils.i(getClass(), "registerMethod method-name: " + method.getName() + " , methodId: " + methodId);
            map.put(methodId, method);
        }
    }

    /**
     * 缓存class
     *
     * @param serviceCls
     */
    private void registerClass(Class serviceCls) {
        LogUtils.i(getClass(), "registerClass serviceCls-name: " + serviceCls.getName());
        mRawClassMap.putIfAbsent(serviceCls.getName(), serviceCls);
    }

    public Class getClassType(String className) {
        if (TextUtils.isEmpty(className))
            return null;

        Class aClass = mRawClassMap.get(className);
        if (aClass == null) {
            try {
                aClass = Class.forName(className);
            } catch (ClassNotFoundException e) {
                LogUtils.e(getClass(), e);
            }
        }
        return aClass;
    }

    public Method getMethod(Class<?> aClass, RequestBean requestBean) {
        String methodName = requestBean.getMethodName();//setFriend()
        if (methodName != null) {
            mRawMethodMap.putIfAbsent(aClass, new ConcurrentHashMap<String, Method>());
            ConcurrentHashMap<String, Method> methods = mRawMethodMap.get(aClass);
            Method method = methods.get(methodName);
            if(method != null){
                return method;
            }
            int pos = methodName.indexOf('(');

            Class[] paramters = null;
            RequestParameter[] requestParameters = requestBean.getRequestParameters();
            if (requestParameters != null && requestParameters.length > 0) {
                paramters = new Class[requestParameters.length];
                for (int i=0;i<requestParameters.length;i++) {
                    paramters[i]=getClassType(requestParameters[i].getParamClsName());
                }
            }
            method = TypeUtils.getMethod(aClass, methodName.substring(0, pos), paramters);
            methods.put(methodName, method);
            return method;
        }
        return null;
    }
}
